#-*- coding:Utf-8 -*-

from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.gui.OnscreenText import OnscreenText
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import * 
from direct.task import Task 
from direct.distributed.PyDatagram import PyDatagram 
from direct.distributed.PyDatagramIterator import PyDatagramIterator 
from Server import *
from Niveau import *
import sys

#Classe du serveur de Jeu
class World(DirectObject):
    #nbequipe, nbparcelles, nbcasesparparcelles, modejeu (1-randball, 2-fps)
    def __init__(self, nbEquipe, tailleLaby, tailleParc, modeJeu):

        self.nbEquipe=nbEquipe
        self.tailleLaby=tailleLaby
        self.tailleParcelles=tailleParc
        self.modeJeu=modeJeu
        
        #On crée un joli niveau
        laby3D={}
        #Model des murs
        laby3D["boxmodel"]="../assets/eggs/box"
        #Echelle des murs
        laby3D["scale"]=0.5
        #Liste des murs présents, complété ensuite par là génération du niveau (genererLaby)
        laby3D['murs']=[]
        #La map, fixe les bords, le look du sol, plafond etc..
        world={}
        #Chargement du model 
        world["model"]="../assets/eggs/ground"
        #La taille
        world["scale"]=42
        world["maxdistance"]=400
        self.niveau=Niveau(self.nbEquipe,laby3D, world,self.tailleLaby ,self.tailleParcelles, self.modeJeu)

        #Prépare l'affichage du world (decors arrière et limites) via les infos du niveau
        self.world = loader.loadModel(self.niveau.world["model"])
        self.world.setPos(self.niveau.world["pos"][0],self.niveau.world["pos"][1], self.niveau.world["pos"][2])
        self.world.setScale(self.niveau.world["scale"])
        self.worldsize=self.niveau.world["size"]
        self.maxdistance=self.niveau.world["maxdistance"]
        self.world.reparentTo(render)

        #Pour chaque murs du labyrinthe on crée un model, correspondant à un model et des positions
        for i in range(len(self.niveau.laby3D["murs"])):
            mur=loader.loadModel(self.niveau.laby3D["boxmodel"])
            mur.setScale(self.niveau.laby3D["scale"])
            mur.setPos(self.niveau.laby3D["murs"][i][0],self.niveau.laby3D["murs"][i][1],self.niveau.laby3D["murs"][i][2])
            mur.reparentTo(render)#Affichage
            
        #Chargement centre, spawns, paniers
        #Egg des bords, echelle des bords, egg du centre, echelle du centre, echelle des paniers
        self.initSpawnCentre("../assets/eggs/untitled", 0.5, "../assets/eggs/boxold", 10, 10)
        
        # {int:{}}
        #Un dictionnaire trié par id de joueur(client) qui contient toutes les infos sur lui
        self.joueurs = {}

        # Démarrage du serveur
        self.server = Server(9099, compress=True)
        
        # On créer une tache pour envoyers les données
        taskMgr.doMethodLater(0, self.printTask, "printData")

    #Nom à changer, tâche qui recoit/envoit les données aux clients
    def printTask(self, task):

        #print "Received: " + str(self.server.getData())
        #print "Clients: " + str(self.server.getClients())

        #recup données et maj joueur
        #Pour chaque joueur qu'on a enregistré
        for cleJ, valJ in self.joueurs.items():
            present=False
            #S'il est toujours connecté
            if cleJ in self.server.activeConnections :
                present=True
            #Sinon KICK DAT FUCKING NOOB !
            if not present:
                self.joueurs[cleJ]["actor"].removeNode()
                del self.joueurs[cleJ]
        #On recupère les zolis données reçus de la part de nos joueurs
        data = self.server.getData()

        #On traite !
        for i in range(len(data)):
            #Si j'ai bien des joueurs identifiés
            if "ident" in data[i]:
                #On mettra à jour leurs données
                if data[i]["ident"] in self.joueurs:
                    #On met ici à jour leur position
                    #TODO : recevoir une indication de ce que le joueur fait, c'est le serveur qui doit dire s'il peut effectivement bougé
                    #pas le client, le joueur envoi des données disant qu'il avance, le serveur actualise les positions
                    self.joueurs[data[i]["ident"]]["actor"].setX(data[i]["posx"])
                    self.joueurs[data[i]["ident"]]["actor"].setY(data[i]["posy"])
                    self.joueurs[data[i]["ident"]]["actor"].setZ(data[i]["posz"])
                    self.joueurs[data[i]["ident"]]["posx"]=self.joueurs[data[i]["ident"]]["actor"].getX()
                    self.joueurs[data[i]["ident"]]["posy"]=self.joueurs[data[i]["ident"]]["actor"].getY()
                    self.joueurs[data[i]["ident"]]["posz"]=self.joueurs[data[i]["ident"]]["actor"].getZ()
                else : #On crée un nouveau joueur, on lui crée son acteur, on le reconnait, on lui donne une position
                    #TODO : le serveur donne la position, et non l'inverse
                    nouveauJoueur = loader.loadModel(data[i]["model"])
                    nouveauJoueur.setPos(data[i]["posx"], data[i]["posy"], data[i]["posz"])
                    nouveauJoueur.setScale(0.002)
                    nouveauJoueur.reparentTo(render)
                    infos={}
                    infos["actor"]=nouveauJoueur
                    infos["model"]=data[i]["model"]
                    infos["posx"]=nouveauJoueur.getX()
                    infos["posy"]=nouveauJoueur.getY()
                    infos["posz"]=nouveauJoueur.getZ()
                    self.joueurs[data[i]["ident"]]=infos

        #renvoi (broadcast) des infos sur les joueurs et la map
        #TODO : à optimiser, n'envoyer que les positions des joueurs, des id de leur skin, et la map seulement si des changements ont lieu
        #self.server.broadcastData(str(self.niveau)+";;"+str(self.joueurs))

        dataEnvoi={}
        dataEnvoi.clear()
        dataEnvoi['partie']=[]
        dataEnvoi['world']={}
        dataEnvoi['players']=[]

        dataEnvoi['partie'].append(self.nbEquipe)
        dataEnvoi['partie'].append(self.tailleLaby)
        dataEnvoi['partie'].append(self.tailleParcelles)
        dataEnvoi['partie'].append(self.modeJeu)
        
        dataEnvoi['world']['murs']=self.niveau.laby3D
        dataEnvoi['world']['world']=self.niveau.world

        self.server.broadcastData(dataEnvoi)
        return Task.again#Et on recommence !


    #Egg des bords, echelle des bords, egg du centre, echelle du centre, echelle des paniers
    def initSpawnCentre(self, eggBords, scaleBords, eggCentre, scaleCentre, scalePaniers):
        #Affichages des bords de la map
        lgLab=self.niveau.labyrinthe.taille #Nombre de parcelles par ligne
	lgParc=self.niveau.labyrinthe.parcelles[0].taille
	nbCasesLigne=lgLab*lgParc
	y=-1
	x=-1
        if(self.nbEquipe==4):
            equipe=True
        else :
            equipe=False
        while (x != nbCasesLigne):
            if(self.nbEquipe<=2):
                mur=loader.loadModel(eggBords)
                mur.setScale(scaleBords)
                mur.setPos(x,y,0)
                mur.reparentTo(render)
            elif (self.nbEquipe>2):
                if(equipe==True):
                    if((x<(((nbCasesLigne-1)/2)-((lgParc-1)/2)+1)or x>(((nbCasesLigne-1)/2)+((lgParc-1)/2))+1)):
                        mur=loader.loadModel(eggBords)
                        mur.setScale(scaleBords)
                        mur.setPos(x,y,0)
                        mur.reparentTo(render)
                else :
                    mur=loader.loadModel(eggBords)
                    mur.setScale(scaleBords)
                    mur.setPos(x,y,0)
                    mur.reparentTo(render)
            x=x+1
            if( x== nbCasesLigne and y==-1):
                x=-1
                y=nbCasesLigne
                equipe=True
                if(self.nbEquipe==4):
                    equipe=True
                
        y=-1
        x=-1
        while (y != nbCasesLigne):
            if(y<(((nbCasesLigne-1)/2)-((lgParc-1)/2)+1)or y>(((nbCasesLigne-1)/2)+((lgParc-1)/2))+1):
                mur=loader.loadModel(eggBords)
                mur.setScale(scaleBords)
                mur.setPos(x,y,0)
                mur.reparentTo(render)
            y=y+1
            if( y== nbCasesLigne and x==-1):
                y=-1
                x=nbCasesLigne


        #######Les Spawns
        #Nord
            pos=((lgLab-1)/2)*lgParc
            panier=loader.loadModel("../assets/eggs/boxold")
            panier.setScale(scalePaniers)
            panier.setPos(-scalePaniers,pos,0)
            panier.reparentTo(render)

        #Sud
            panier=loader.loadModel("../assets/eggs/boxold")
            panier.setScale(scalePaniers)
            posy=(lgLab*lgParc)
            panier.setPos(posy,pos,0)
            panier.reparentTo(render)

        #Est
            if(self.nbEquipe>=3):
                pos=((lgParc)*((lgLab-1)/2))
                panier=loader.loadModel("../assets/eggs/boxold")
                panier.setScale(scalePaniers)
                posy=(lgLab*lgParc)
                panier.setPos(pos,posy,0)
                panier.reparentTo(render)
       
         #Ouest
            if(self.nbEquipe==4):
                pos=((lgParc)*((lgLab-1)/2))
                panier=loader.loadModel("../assets/eggs/boxold")
                panier.setScale(scalePaniers)
                panier.setPos(pos,-scalePaniers,0)
                panier.reparentTo(render)
        
        #Si mode randball on ajoute centre et paniers  
        if(self.modeJeu==1):
            #Le centre
            pos=((lgLab*lgParc)/2)-(lgParc/2)
            centre=loader.loadModel(eggCentre)
            centre.setScale(scaleCentre)
            centre.setPos(pos,pos,0)
            centre.reparentTo(render)
            
            #######Les paniers
            ####Nord
            pos=((lgLab-1)/2)*lgParc
            panier=loader.loadModel("../assets/eggs/boxold")
            panier.setScale(scalePaniers)
            panier.setPos(0,pos,0)
            panier.reparentTo(render)

            ####Sud
            panier=loader.loadModel("../assets/eggs/boxold")
            panier.setScale(scalePaniers)
            posy=(lgLab*lgParc)-scalePaniers
            panier.setPos(posy,pos,0)
            panier.reparentTo(render)
            
            ####Est
            if(self.nbEquipe>=3):
                pos=((lgParc)*((lgLab-1)/2))
                panier=loader.loadModel("../assets/eggs/boxold")
                panier.setScale(scalePaniers)
                posy=(lgLab*lgParc)-scalePaniers
                panier.setPos(pos,posy,0)
                panier.reparentTo(render)

                
            ####Ouest
            if(self.nbEquipe==4):
                pos=((lgParc)*((lgLab-1)/2))
                panier=loader.loadModel("../assets/eggs/boxold")
                panier.setScale(scalePaniers)
                panier.setPos(pos,0,0)
                panier.reparentTo(render)
        

#nbequipe, nbparcelles, nbcasesparparcelles, modejeu (1-randball, 2-fps)
w=World(4,7,10, 1)#Creation du monde
run()#ET ACTION !
